import { forwardRef, useEffect, useImperativeHandle, useState } from 'react'
import {
  FlatList,
  View,
  NativeSyntheticEvent,
  NativeScrollEvent,
  StyleSheet,
  ActivityIndicator,
  Text,
} from 'react-native'
import type {
  OwlWaterfallProp,
  FlatListData,
  OwlWaterfallItemLayout,
} from './owlWaterfallType'
import { GoodsDataItem } from '../../assets/data/data'
import CustomFreshControl from '../refreshControl/refreshControl'

export default forwardRef(function OwlWaterfall(props: OwlWaterfallProp, ref) {
  const [keyHeightObj, setKeyHight] = useState<{
    [key: number | string]: number
  }>({})
  const [flatListData, setFlatListData] = useState<FlatListData[][]>([[], []])
  const [finishedIndex, setFinishedIndex] = useState({
    left: 0,
    right: 0,
  })
  // const [scrollTop, setScrollTop] = useState(0) // 距离视图top滚动的距离
  const [refreshing, setRefreshing] = useState(false)
  const [loading, setLoading] = useState(false)
  const redrawLayout = function (newKeyHeightObj: any = {}) {
    setFlatListData(val => {
      const totalLng = val.reduce((prev, next) => {
        return prev + next.length
      }, 0)
      // 如果还没全部加载出来高度则不动
      if (!totalLng || Object.keys(newKeyHeightObj).length !== totalLng) {
        return val
      }
      let i = 0,
        left = 0,
        right = 0,
        leftI = 0,
        rightI = 0,
        lng = 0
      let leftArr = val[0].slice(finishedIndex.left),
        rightArr = val[1].slice(finishedIndex.right) //没有排序的数组
      let leftLng = leftArr.length,
        rightLng = rightArr.length
      const arr = [] // 把没有排序的左和右数组变成一个数组
      const ret: FlatListData[][] = [
        val[0].slice(0, finishedIndex.left),
        val[1].slice(0, finishedIndex.right),
      ]
      lng = leftLng + rightLng
      while (lng > i) {
        if (leftLng > leftI) {
          arr.push(leftArr[leftI++])
          i++
        }
        if (rightLng > rightI) {
          arr.push(rightArr[rightI++])
          i++
        }
      }
      i = 0

      while (lng > i) {
        const key = arr[i]._key
        const height = keyHeightObj[key]
        if (left > right) {
          ret[1].push(arr[i])
          right = Math.ceil(right + height)
          i++
        } else {
          ret[0].push(arr[i])
          left = Math.ceil(left + height)
          i++
        }
      }

      setFinishedIndex({
        left: ret[0].length,
        right: ret[1].length,
      })
      setRefreshing(false)
      setLoading(false) //渲染完毕
      return ret
    })
  }

  function getNewData(data: any[]) {
    const now = Date.now().toString().substring(8)
    return data.map((item, i) => ({ ...item, _key: item.id + now || i + now }))
  }
  //初始化
  useEffect(() => {
    if (!props.data.length) {
      return
    }
    const data = getNewData(props.data)
    setFlatListData(arrSeparateTwo(data))
  }, [])

  useImperativeHandle(
    ref,
    () => ({
      resetData(data: GoodsDataItem[]) {
        const newData: FlatListData[] = getNewData(data)
        let arr = arrSeparateTwo(newData)
        setKeyHight({})
        setFinishedIndex({
          left: 0,
          right: 0,
        })
        setFlatListData(arr)
      },
      appendData(data: GoodsDataItem[]) {
        setFlatListData(val => {
          const newData: FlatListData[] = getNewData(data)
          let arr = arrSeparateTwo(newData)
          const ret = val.map((item, i) => item.concat(arr[i]))
          return ret
        })
      },
    }),
    [],
  )
  useEffect(() => {
    const totalLng = flatListData.reduce((prev, next) => {
      return prev + next.length
    }, 0)
    // 如果还没全部加载出来高度则不动
    if (Object.keys(keyHeightObj).length !== totalLng) {
      return
    }
  }, [flatListData, keyHeightObj])

  async function onRefresh() {
    if (!props.onRefresh || refreshing) return
    setRefreshing(true)

    await (props.onRefresh && props.onRefresh())
    setRefreshing(false)
  }

  function onScroll(event: NativeSyntheticEvent<NativeScrollEvent>) {
    const { layoutMeasurement, contentSize, contentOffset } = event.nativeEvent
    if (layoutMeasurement.height > contentSize.height || refreshing) return
    if (
      props.onScrollBottom &&
      contentOffset.y + layoutMeasurement.height + 100 >= contentSize.height
    ) {
      emitScrollBottom()
    }
  }

  function arrSeparateTwo<T = any>(data: T[]) {
    let i = 0,
      lng = data.length
    const arr: T[][] = [[], []]
    while (lng > i) {
      arr[0].push(data[i])
      i++
      if (lng > i) {
        arr[1].push(data[i])
        i++
      }
    }
    return arr
  }

  async function emitScrollBottom() {
    if (loading) return
    setLoading(true)
    await (props.onScrollBottom && props.onScrollBottom())
  }

  // 图片加载出来后
  const onLayout = (_key: number) => (e: OwlWaterfallItemLayout) => {
    if (!(_key in keyHeightObj)) {
      setKeyHight(val => {
        const newVal = Object.assign({}, val, {
          [_key]: parseFloat(e.height.toFixed(2)),
        })
        redrawLayout(newVal)
        return newVal
      })
    }
  }

  return (
    <View style={styles.box}>
      <FlatList
        data={['list', 'loading']}
        onScroll={onScroll}
        scrollEventThrottle={16}
        style={styles.listWrap}
        refreshControl={
          <CustomFreshControl refreshing={refreshing} onRefresh={onRefresh} />
        }
        renderItem={({ item }) => {
          switch (item) {
            case 'list':
              return (
                <View style={styles.list}>
                  {flatListData.map((col, index) => (
                    <View
                      key={index}
                      style={{
                        flex: 1,
                        width: '100%',
                        paddingLeft: index === 1 ? 6 : 12,
                        paddingRight: index === 0 ? 6 : 12,
                      }}
                    >
                      {col.map((row, key) => (
                        <View
                          key={row._key}
                          style={{
                            opacity:
                              index === 0
                                ? key < finishedIndex.left
                                  ? 1
                                  : 0
                                : key < finishedIndex.right
                                  ? 1
                                  : 0,
                          }}
                        >
                          {props.renderItem(row, onLayout(row._key))}
                        </View>
                      ))}
                    </View>
                  ))}
                </View>
              )
            case 'loading':
              return (
                <View style={[styles.loading, { opacity: loading ? 1 : 0 }]}>
                  <ActivityIndicator color="#666" size={12} />
                  <Text style={styles.loadingTxt}>正在加载更多</Text>
                </View>
              )
            default:
              return <></>
          }
        }}
      />
    </View>
  )
})

const styles = StyleSheet.create({
  box: {
    position: 'relative',
    height: '100%',
  },
  listWrap: {
    paddingTop: 12,
  },
  list: {
    display: 'flex',
    alignItems: 'flex-start',
    flexDirection: 'row',
    width: '100%',
  },
  loading: {
    width: '100%',
    display: 'flex',
    alignItems: 'center',
    flexDirection: 'row',
    justifyContent: 'center',
    paddingBottom: 40,
  },
  loadingTxt: {
    marginLeft: 12,
    color: '#999',
    fontSize: 16,
  },
})
